
#ifndef _UNSIGNED_INTEGER_H_
#define _UNSIGNED_INTEGER_H_

#include "Basic.hpp"

#ifdef _x64_
typedef unsigned long long	ULONG;
#else
typedef unsigned long	ULONG;
#endif

class UnsignedInteger{
public:
	ULONG value;
	
	const static ULONG MAX_VALUE = ~0;
	
	CALLCONV UnsignedInteger(ULONG i=0){
		value = i;
	}
	
	CALLCONV UnsignedInteger(char *str, UINT8 radix=10){
		value = 0;
		if(str == (char*)0)
		#ifdef _EXCEPTION_H_
			throw NullPointerException(
				"Attempt to construct an UnsignedInteger object with NULL string");
		#else
			return;
		#endif
		else if(radix < 2 || radix > 36)
		#ifdef _EXCEPTION_H_
			throw InvalidArgumentException(
				"Attempt to construct an UnsignedInteger object with an invalid radix");
		#else
			return;
		#endif
		else{
			char c;
			for(; (c = *str) != 0; str++){
				if(c >= '0' && c <= '9'){
					c -= '0';
				}else if(c >= 'A' && c <= 'Z'){
					c -= 'A' - 10;
				}else if(c >= 'a' && c <= 'z'){
					c -= 'a' - 10;
				}else{
				#ifdef _EXCEPTION_H_
					throw NumberFormatException();
				#endif
					break;
				}
				if(c >= radix){
				#ifdef _EXCEPTION_H_
					throw NumberFormatException();
				#endif
					break;
				}
				value = value * radix + c;
			}
		}
	}
	
	inline int compareTo(ULONG i){
		return (value > i) ? 1 : (value < i ? -1 : 0);
	}
	
	inline int compareTo(UnsignedInteger ui){
		return compareTo(ui.value);
	}
	
	CALLCONV char* toString(char* buffer, UINT8 radix=10){
		char temp[8 * sizeof(ULONG)];
		if(this == (UnsignedInteger*)0)
		#ifdef _EXCEPTION_H_
			throw NullPointerException(
				"Attempt to convert a NULL UnsignedInteger to a string");
		#else
			return (char*)0;
		#endif
		if(buffer == (char*)0)
		#ifdef _EXCEPTION_H_
			throw NullPointerException(
				"Attempt to convert a UnsignedInteger to a NULL string");
		#else
			return (char*)0;
		#endif
		if(radix < 2 || radix > 36)
		#ifdef _EXCEPTION_H_
			throw InvalidArgumentException(
				"Attempt to convert an UnsignedInteger object to a string with an invalid radix");
		#else
			return (char*)0;
		#endif
		
		if(value == 0){
			buffer[0] = '0'; buffer[1] = 0;
			return buffer;
		}
		int i = 0, j = 0;
		ULONG q = value, r;
		while(q != 0){
			r = q % radix;
			q = q / radix;
			temp[i] = r + '0';
			if(temp[i] > '9') temp[i] += 'A'-'9'-1;
			i++;
		}
		do{
			buffer[j++] = temp[--i];	// inverse the order
		}while(i > 0);
		buffer[j] = 0;	// end string
		return buffer;
	}
	
	
	UnsignedInteger& operator ++(){
		++value;
		return *this;
	}
	
	UnsignedInteger& operator --(){
		--value;
		return *this;
	}
	
	UnsignedInteger& operator +=(UnsignedInteger ui){
		value += ui.value;
		return *this;
	}
	
	UnsignedInteger& operator -=(UnsignedInteger ui){
		value -= ui.value;
		return *this;
	}
	
	UnsignedInteger& operator *=(UnsignedInteger ui){
		value *= ui.value;
		return *this;
	}
	
	UnsignedInteger& operator /=(UnsignedInteger ui){
		value /= ui.value;
		return *this;
	}
	
	UnsignedInteger& operator %=(UnsignedInteger ui){
		value %= ui.value;
		return *this;
	}
	
	UnsignedInteger& operator |=(UnsignedInteger ui){
		value |= ui.value;
		return *this;
	}
	
	UnsignedInteger& operator &=(UnsignedInteger ui){
		value &= ui.value;
		return *this;
	}
	
	UnsignedInteger& operator ^=(UnsignedInteger ui){
		value ^= ui.value;
		return *this;
	}
	
	UnsignedInteger& operator <<=(unsigned n){
		value <<= n;
		return *this;
	}
	
	UnsignedInteger& operator >>=(unsigned n){
		value >>= n;
		return *this;
	}
	
	
	UnsignedInteger& operator =(ULONG n){
		value = n;
		return *this;
	}
	
	UnsignedInteger& operator +=(ULONG n){
		value += n;
		return *this;
	}
	
	UnsignedInteger& operator -=(ULONG n){
		value -= n;
		return *this;
	}
	
	UnsignedInteger& operator *=(ULONG n){
		value *= n;
		return *this;
	}
	
	UnsignedInteger& operator /=(ULONG n){
		value /= n;
		return *this;
	}
	
	UnsignedInteger& operator %=(ULONG n){
		value %= n;
		return *this;
	}
	
	UnsignedInteger& operator |=(ULONG n){
		value |= n;
		return *this;
	}
	
	UnsignedInteger& operator &=(ULONG n){
		value &= n;
		return *this;
	}
	
	UnsignedInteger& operator ^=(ULONG n){
		value ^= n;
		return *this;
	}
	
	
	UnsignedInteger operator +(UnsignedInteger ui){
		return UnsignedInteger(value + ui.value);
	}
	
	UnsignedInteger operator -(UnsignedInteger ui){
		return UnsignedInteger(value - ui.value);
	}
	
	UnsignedInteger operator *(UnsignedInteger ui){
		return UnsignedInteger(value * ui.value);
	}
	
	UnsignedInteger operator /(UnsignedInteger ui){
		return UnsignedInteger(value / ui.value);
	}
	
	UnsignedInteger operator %(UnsignedInteger ui){
		return UnsignedInteger(value % ui.value);
	}
	
	UnsignedInteger operator |(UnsignedInteger ui){
		return UnsignedInteger(value | ui.value);
	}
	
	UnsignedInteger operator &(UnsignedInteger ui){
		return UnsignedInteger(value & ui.value);
	}
	
	UnsignedInteger operator ^(UnsignedInteger ui){
		return UnsignedInteger(value ^ ui.value);
	}
	
	UnsignedInteger operator <<(unsigned n){
		return UnsignedInteger(value << n);
	}
	
	UnsignedInteger operator >>(unsigned n){
		return UnsignedInteger(value >> n);
	}
	
	
	UnsignedInteger operator +(ULONG n){
		return UnsignedInteger(value + n);
	}
	
	UnsignedInteger operator -(ULONG n){
		return UnsignedInteger(value - n);
	}
	
	UnsignedInteger operator *(ULONG n){
		return UnsignedInteger(value * n);
	}
	
	UnsignedInteger operator /(ULONG n){
		return UnsignedInteger(value / n);
	}
	
	UnsignedInteger operator %(ULONG n){
		return UnsignedInteger(value % n);
	}
	
	UnsignedInteger operator |(ULONG n){
		return UnsignedInteger(value | n);
	}
	
	UnsignedInteger operator &(ULONG n){
		return UnsignedInteger(value & n);
	}
	
	UnsignedInteger operator ^(ULONG n){
		return UnsignedInteger(value ^ n);
	}
	
	
	bool operator >(UnsignedInteger ui){
		return value > ui.value;
	}
	
	bool operator >=(UnsignedInteger ui){
		return value >= ui.value;
	}
	
	bool operator <(UnsignedInteger ui){
		return value < ui.value;
	}
	
	bool operator <=(UnsignedInteger ui){
		return value <= ui.value;
	}
	
	bool operator ==(UnsignedInteger ui){
		return value == ui.value;
	}
	
	bool operator !=(UnsignedInteger ui){
		return value != ui.value;
	}
	
	
	bool operator >(ULONG n){
		return value > n;
	}
	
	bool operator >=(ULONG n){
		return value >= n;
	}
	
	bool operator <(ULONG n){
		return value < n;
	}
	
	bool operator <=(ULONG n){
		return value <= n;
	}
	
	bool operator ==(ULONG n){
		return value == n;
	}
	
	bool operator !=(ULONG n){
		return value != n;
	}
}; // class UnsignedInteger
#endif // _UNSIGNED_INTEGER_H_
